package com.csc.finalproject.dao;

import java.lang.reflect.ParameterizedType;
import java.util.List;
import java.util.Map;
import java.lang.reflect.Type;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.TypedQuery;

import org.springframework.stereotype.Repository;


/**
 * implement of generic dao
 * 
 * @author Phuc create date : 19/8/2014
 */


public abstract class GenericDAOImpl<T> implements GenericDAO<T> {

	@PersistenceContext
	protected EntityManager em;

	private Class<T> type;

	public GenericDAOImpl() {
		Type t = (Type) getClass().getGenericSuperclass();
		ParameterizedType pt = (ParameterizedType) t;
		type = (Class) pt.getActualTypeArguments()[0];
	}

	/**
	 * function number row of table in database
	 * 
	 * @param params
	 * @return number row in table
	 */
	@Override
	public long countAll(final Map<String, Object> params) {
		final StringBuffer queryString = new StringBuffer(
				"SELECT count(*) from ");
		queryString.append(type.getSimpleName()).append(" o ");
		// queryString.append(this.getQueryClauses(params, null));

		final Query query = this.em.createQuery(queryString.toString());
		return (Long) query.getSingleResult();
	}

	/**
	 * fuction get all row of table in database
	 * 
	 * @return all row in table
	 */
	@Override
	public List<T> getAll() {

		final StringBuffer queryString = new StringBuffer("From ");
		queryString.append(type.getSimpleName());
		

		final Query query = this.em.createQuery(queryString.toString());
		return query.getResultList();
	}

	/**
	 * create object type T and return
	 * 
	 * @param t
	 * @return object <T>
	 */
	@Override
	public T create(T t) {
		this.em.persist(t);
		return t;
	}

	/**
	 * delete object from database
	 * 
	 * @param id
	 * 
	 */
	@Override
	public void delete(Object id) {
		this.em.remove(this.em.getReference(type, id));
	}

	/**
	 * find object from database with param id
	 * 
	 * @param id
	 * @return object<T>
	 */
	@Override
	public T find(Object id) {
		return this.em.find(type, id);
	}

	/**
	 * update object to database and return object
	 * 
	 * @param t
	 * @return object after update
	 */
	@Override
	public T update(T t) {
		return this.em.merge(t);
	}

}
